﻿using DataWorks_Tools.BasicMethods;
using DataWorks_Tools.MappModals;
using DataWorks_Tools.MergeDetails;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace DataWorks_Tools.SpikeDetails
{
    public class SpikeDetailsMethods
    {
        /// <summary>
        /// 该方法接受一个字符串列表作为输入数据，以及要替换的列号，起始行数和新数据（部分数据）。
        /// </summary>
        /// <param name="od"></param>
        /// <param name="columntoreplace"></param>
        /// <param name="nd"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public static async Task ReplaceColumnInCSV(List<string> od, int columntoreplace, int startrow, List<double> nd)
        {
            await Task.Run(() =>
            {
                //这里i要从1开始，因为od里的第0行是列名，不是数据
                for (int i = 1; i < od.Count; i++)
                {
                    // Split the line into an array of columns
                    string[] columns = od[i].Split(',');

                    // Check if the column index is within the range
                    if (columntoreplace >= 0 && columntoreplace < columns.Length)
                    {
                        // Replace the column with new data
                        //判断是否到了起始行并且小于最后一个，则开始替换
                        if (i >= startrow && i <= startrow + nd.Count - 1)
                        {
                            columns[columntoreplace] = nd[i - startrow].ToString();
                        }
                    }
                    else
                    {
                        throw new Exception($"列号超出界限: {columntoreplace}");
                    }
                    //替换原来的每一行string
                    od[i] = string.Join(",", columns);
                }
            });
        }
        /// <summary>
        /// 用户输入的去除spike的通道列号要做处理，比如里面有1-10这种
        /// </summary>
        /// <param name="spikeidx"></param>
        /// <returns></returns>
        public static List<int> YXHGetSpikeIdx(string[] spikeidx)
        {
            List<int> indexlists = new List<int>();
            for (int i = 0; i < spikeidx?.Length; i++)
            {
                if (int.TryParse(spikeidx[i], out int d))
                {
                    indexlists.Add(d);
                }
                else
                {
                    if (spikeidx[i].Contains('-'))
                    {
                        var ct = spikeidx[i].Split('-');
                        if (ct.Length == 2)
                        {
                            var bct0 = int.TryParse(ct[0], out int ct0);
                            var bct1 = int.TryParse(ct[1], out int ct1);
                            if (bct0 && bct1)
                            {
                                indexlists.AddRange(Enumerable.Range(ct0, ct1 - ct0 + 1).ToArray());
                            }

                        }
                        else
                        {
                            return new List<int>();
                        }
                    }
                    else
                    {
                        return new List<int>();
                    }
                }
            }
            //去重数字
            indexlists = indexlists.Distinct().ToList();
            return indexlists;
        }

        /// <summary>
        /// 毛刺修正程序的目前使用版本
        /// </summary>
        /// <param name="row"></param>
        /// <returns></returns>
        public static async Task<List<string>> YXHExcuteSpikeMultiThreadsAsync(SpikeModal row)
        {
            List<string> list = new List<string>();//专用于输出程序计算过程中的错误信息
            List<FileInfo[]> fileInfos_txtcombined = new List<FileInfo[]>();
            //存放每个日期文件夹下的原始文件集
            List<FileInfo[]> fileInfos_od = new List<FileInfo[]>();
            //先判断在每个日期文件夹下停车合并的文件集第一个文件名是否在原始文件集里面，如果有就执行这个文件夹下的操作，如果没有说明
            //路径选错了
            try
            {
                Stopwatch timer = new Stopwatch();
                timer.Start();
                Directory.CreateDirectory(row.rdpath);
                //获得停车合并路径下的日期文件夹列表如（03_01,03_02,03_03)
                var ds_txtcombined = BasicFilesOperation.YXHGetProcessedDateDir(row.referdir, row.rdpath, row.datedir);
                //获得源数据日期文件夹列表如（03_01,03_02,03_03)
                var ds_od = BasicFilesOperation.YXHGetProcessedDateDir(row.odpath, row.rdpath, row.datedir);
                //先按合并的日期文件夹来一个个循环
                foreach (var txtdir in ds_txtcombined)
                {
                    //获得每个合并的日期文件夹下的所有csv文件，每个文件进行多线程处理，这里需要合并后的数据是因为毛刺检测是需要在合并后的数据里进行
                    var txtcombinedcsvs = BasicFilesOperation.YXHGetAllextFiles(txtdir.FullName, "*.csv");
                    //判断原始日期文件夹列表里有没有对应的日期文件夹
                    if (ds_od.Any(a => a.Name == txtdir.Name))
                    {
                        //从源路径和日期文件夹生成od的日期文件夹路径
                        var oddir = Path.Combine(row.odpath, txtdir.Name);
                        //获得原路径下的所有csv文件
                        var odcsvs = BasicFilesOperation.YXHGetAllextFiles(oddir, "*.csv");
                        //获得保存的路径
                        var rddatedir=Path.Combine(row.rdpath, txtdir.Name);
                        Directory.CreateDirectory(rddatedir);
                        //准备多线程
                        List<Task<List<string>>> tasks = new List<Task<List<string>>>();
                        foreach (var txtcsv in txtcombinedcsvs)
                        {
                            Task<List<string>> task = Task.Run(async () =>
                            {
                                List<string> result = new List<string>();
                                //利用csvhelper来读取合并数据的特定列号的数据的数据行数
                                var txtcsvcount = CSVHelperClass.GetDataFromColumnIdx(txtcsv, 0).Count;
                                //说明能整除2560
                                if (true)
                                {
                                    //把合并的csv数据拆分成2个文件名,fileinfo.name是带扩展名的，所以第一个sp[0]需要给它加上扩展名
                                    var sp = txtcsv.Name.Split("-to-");
                                    if (sp.Length == 2)
                                    {
                                        sp[0] += ".csv";
                                        //获取两个名称之间的数据集
                                        var betweencsv = odcsvs.YXHFindDataBetweenNames(sp[0], sp[1]);
                                        List<int> csvsrowcount = new List<int>();
                                        //这里需要计算保存一下betweencsv每个文件的行数（不算标题行）
                                        foreach (var csv in betweencsv)
                                        {
                                            csvsrowcount.Add(csv.FullName.GetCsvRowDataCount());
                                        }
                                        //判断数据集个数与合并csv的行数是否对应一致
                                        if (true)
                                        {
                                            //一个个去读取停车合并后的csv文件数据.读取每一个csv数据到List<string>,每一行为一个string，包括标题行
                                            //读取csv多个特定列的数据到List<List<double>>>，这是需要去除spike的数据集，不包括标题行
                                            List<List<double>> datalists = new List<List<double>>();
                                            for (int j = 0; j < row.spikeidx.Count; j++)
                                            {
                                                var t = CSVHelperClass.GetDataFromColumnIdx(txtcsv, row.spikeidx[j]);
                                                datalists.Add(t);
                                            }
                                            //存储处理每个停车合并文件spike的SpikeinFileClass类数据集
                                            List<SpikeinFileClass> totalonetxtcombinedfile = new List<SpikeinFileClass>();
                                            //对每一个指定列里的数据进行spike检测
                                            for (int j = 0; j < row.spikeidx.Count; j++)
                                            {
                                                //获得去除spike后的某指定列的数据类
                                                var spikeremovelist = RemoveSpikeProcess.SpikeRemovalProcess(datalists[j], row.meanpoints, row.vairancepoints, row.threadspercentage, row.ratio, row.spikeidx[j], row.pointcounts,csvsrowcount);
                                                if (spikeremovelist != null)
                                                {
                                                    totalonetxtcombinedfile.AddRange(spikeremovelist);
                                                }
                                                //把去除spike后的数据替换到原数据
                                            }
                                            //把相同索引号的分在一起，因为spikefileindex相同的数据即为同一个文件的不同通道的数据
                                            var groupdata = totalonetxtcombinedfile.GroupBy(s => s.spikefileindex);
                                            // 遍历每个组别并取出数据，每个组别就是相同文件名的一组SpikeinFileClass数据
                                            foreach (var group in groupdata)
                                            {
                                                var eachgroup = group.ToList(); // 获取该组别的数据列表
                                                //fileindexinod此为每一组分组后的序号，比如为2，则spike出现在这一组中的第3个文件
                                                var fileindexinod = eachgroup?.FirstOrDefault()?.spikefileindex;
                                                if (fileindexinod != null)
                                                {
                                                    //读取spike源csv的所有数据
                                                    var odlist = await CSVHelperClass.YXHReadCSV2ListOneTime(betweencsv[(int)fileindexinod]);
                                                    if (eachgroup != null)
                                                    {
                                                        foreach (var c in eachgroup)
                                                        {
                                                            if (c.filtervalue != null)
                                                            {
                                                                await ReplaceColumnInCSV(odlist, c.spikecollumn, c.spikestartrow, c.filtervalue);
                                                            }
                                                        }
                                                    }
                                                    var resultpath = Path.Combine(rddatedir, betweencsv[(int)fileindexinod].Name);
                                                    //这里的odlist是已经修改过了的数据
                                                    await CSVHelperClass.YXHSaveCSVfromListOneTimeAsync(resultpath, odlist);
                                                    //把去除的spike的数据覆盖到原来的路径下
                                                    await CSVHelperClass.YXHSaveCSVfromListOneTimeAsync(betweencsv[(int)fileindexinod].FullName, odlist);
                                                }
                                            }
                                        }
                                    }
                                    else
                                    {
                                        result.Add($"合并文件{txtcsv.Name}只包含一个csv");
                                    }
                                }
                                return result;
                            });
                            tasks.Add(task);
                            await Task.WhenAll(tasks.ToArray());
                            foreach (var t in tasks)
                            {
                                list.AddRange(t.Result);
                            }
                        }
                    }
                    timer.Stop();
                    list.Add($"{txtdir.Name}毛刺去除完成时间为{timer.Elapsed.TotalMinutes.ToString("0.00")}分");
                }
                timer.Stop();
                list.Add($"去毛刺程序总完成时间为{timer.Elapsed.TotalMinutes.ToString("0.00")}分-多线程");
            }
            catch (Exception ex)
            {
                string methodName = "";
                // 获取堆栈跟踪信息
                StackTrace stackTrace = new StackTrace(ex);
                // 获取第一个堆栈帧
                StackFrame? stackFrame = stackTrace.GetFrame(0);
                // 获取方法名
                if (stackFrame != null)
                {
                    var s = stackFrame.GetMethod();
                    if (s != null)
                    {
                        methodName = s.Name;
                    }
                }
                list.Add(methodName + "方法出现了错误：" + ex.StackTrace);
            }
            return list;
        }
    }
}
